using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using System.Xml;
using System.Data;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;

namespace ShopPowerTemplate.Entities
{
    public class EntitiesDBBase : DbContext
    {
        public DbSet<Address> AddressSet { get; set; }
        public DbSet<AppSettings> AppSettingsSet { get; set; }
        public DbSet<Category> CategorySet { get; set; }
        public DbSet<Customer> CustomerSet { get; set; }
        public DbSet<Image> ImageSet { get; set; }
        public DbSet<Option> OptionSet { get; set; }
        public DbSet<OptionType> OptionTypeSet { get; set; }
        public DbSet<Order> OrderSet { get; set; }
        public DbSet<OrderDetail> OrderDetailSet { get; set; }
        public DbSet<OrderState> OrderStateSet { get; set; }
        public DbSet<Product> ProductSet { get; set; }
        public DbSet<ProductDetail> ProductDetailSet { get; set; }
        public DbSet<Review> ReviewSet { get; set; }
        public DbSet<ShippingCost> ShippingCostSet { get; set; }
        public DbSet<Subcategory> SubcategorySet { get; set; }
        public DbSet<User> UserSet { get; set; }

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.Conventions.Remove<System.Data.Entity.ModelConfiguration.Conventions.PluralizingTableNameConvention>();
            ConfigureMapping(modelBuilder);
            base.OnModelCreating(modelBuilder);
        }

        public virtual void ConfigureMapping(DbModelBuilder modelBuilder)
        {
            //Address Properties
            modelBuilder.Entity<Address>().HasKey(k => k.Id);
            modelBuilder.Entity<Address>().Property(p => p.AddressLine1).IsRequired();
            modelBuilder.Entity<Address>().Property(p => p.AddressLine2).IsRequired();
            modelBuilder.Entity<Address>().Property(p => p.City).IsRequired();
            modelBuilder.Entity<Address>().Property(p => p.StateProvince).IsRequired();
            modelBuilder.Entity<Address>().Property(p => p.PostalCode).IsRequired();
            modelBuilder.Entity<Address>().Property(p => p.Country).IsRequired();
            modelBuilder.Entity<Address>().Property(p => p.IsBilling).IsRequired();

            //AppSettings Properties
            modelBuilder.Entity<AppSettings>().HasKey(k => k.Id);
            modelBuilder.Entity<AppSettings>().Property(p => p.AppKey).IsRequired();
            modelBuilder.Entity<AppSettings>().Property(p => p.AppValue).IsRequired();

            //Category Properties
            modelBuilder.Entity<Category>().HasKey(k => k.Id);
            modelBuilder.Entity<Category>().Property(p => p.Name).IsRequired();
            modelBuilder.Entity<Category>().Property(p => p.Description).IsRequired();
            modelBuilder.Entity<Category>().Property(p => p.Image).IsRequired();

            //Customer Properties
            modelBuilder.Entity<Customer>().HasKey(k => k.Id);
            modelBuilder.Entity<Customer>().Property(p => p.FirstName).IsRequired();
            modelBuilder.Entity<Customer>().Property(p => p.LastName).IsRequired();
            modelBuilder.Entity<Customer>().Property(p => p.Email).IsRequired();
            modelBuilder.Entity<Customer>().Property(p => p.SessionId).IsRequired();

            //Image Properties
            modelBuilder.Entity<Image>().HasKey(k => k.Id);
            modelBuilder.Entity<Image>().Property(p => p.Name).IsRequired();
            modelBuilder.Entity<Image>().Property(p => p.Description).IsRequired();
            modelBuilder.Entity<Image>().Property(p => p.SortOrder).IsRequired();
            modelBuilder.Entity<Image>().Property(p => p.Data).IsRequired();

            //Option Properties
            modelBuilder.Entity<Option>().HasKey(k => k.Id);
            modelBuilder.Entity<Option>().Property(p => p.Name).IsRequired();
            modelBuilder.Entity<Option>().Property(p => p.Description).IsRequired();

            //OptionType Properties
            modelBuilder.Entity<OptionType>().HasKey(k => k.Id);
            modelBuilder.Entity<OptionType>().Property(p => p.Name).IsRequired();
            modelBuilder.Entity<OptionType>().Property(p => p.Description).IsRequired();

            //Order Properties
            modelBuilder.Entity<Order>().HasKey(k => k.Id);
            modelBuilder.Entity<Order>().Property(p => p.Reference).IsRequired();
            modelBuilder.Entity<Order>().Property(p => p.Date).IsRequired();
            modelBuilder.Entity<Order>().Property(p => p.ShippingCost).IsRequired();

            //OrderDetail Properties
            modelBuilder.Entity<OrderDetail>().HasKey(k => k.Id);
            modelBuilder.Entity<OrderDetail>().Property(p => p.Quantity).IsRequired();
            modelBuilder.Entity<OrderDetail>().Property(p => p.Price).IsRequired();
            modelBuilder.Entity<OrderDetail>().Property(p => p.Tax).IsRequired();

            //OrderState Properties
            modelBuilder.Entity<OrderState>().HasKey(k => k.Id);
            modelBuilder.Entity<OrderState>().Property(p => p.Name).IsRequired();
            modelBuilder.Entity<OrderState>().Property(p => p.Description).IsRequired();

            //Product Properties
            modelBuilder.Entity<Product>().HasKey(k => k.Id);
            modelBuilder.Entity<Product>().Property(p => p.Name).IsRequired();
            modelBuilder.Entity<Product>().Property(p => p.Description).IsRequired();
            modelBuilder.Entity<Product>().Property(p => p.Price).IsRequired();
            modelBuilder.Entity<Product>().Property(p => p.Tax).IsRequired();
            modelBuilder.Entity<Product>().Property(p => p.Prominent).IsRequired();

            //ProductDetail Properties
            modelBuilder.Entity<ProductDetail>().HasKey(k => k.Id);
            modelBuilder.Entity<ProductDetail>().Property(p => p.Stock).IsRequired();

            //Review Properties
            modelBuilder.Entity<Review>().HasKey(k => k.Id);
            modelBuilder.Entity<Review>().Property(p => p.Date).IsRequired();
            modelBuilder.Entity<Review>().Property(p => p.Rating).IsRequired();
            modelBuilder.Entity<Review>().Property(p => p.Comment).IsRequired();

            //ShippingCost Properties
            modelBuilder.Entity<ShippingCost>().HasKey(k => k.Id);
            modelBuilder.Entity<ShippingCost>().Property(p => p.RangeMin).IsRequired();
            modelBuilder.Entity<ShippingCost>().Property(p => p.RangeMax).IsRequired();
            modelBuilder.Entity<ShippingCost>().Property(p => p.Cost).IsRequired();

            //Subcategory Properties
            modelBuilder.Entity<Subcategory>().HasKey(k => k.Id);
            modelBuilder.Entity<Subcategory>().Property(p => p.Name).IsRequired();
            modelBuilder.Entity<Subcategory>().Property(p => p.Description).IsRequired();

            //User Properties
            modelBuilder.Entity<User>().HasKey(k => k.Id);
            modelBuilder.Entity<User>().Property(p => p.Login).IsRequired();
            modelBuilder.Entity<User>().Property(p => p.Password).IsRequired();


            modelBuilder.Entity<Address>().HasRequired<Customer>(e => e.Customer).WithMany(e => e.Addresses);
            modelBuilder.Entity<Image>().HasRequired<Product>(e => e.Product).WithMany(e => e.Images);
            modelBuilder.Entity<Option>().HasRequired<OptionType>(e => e.OptionType).WithMany(e => e.Options);
            modelBuilder.Entity<Order>().HasRequired<Customer>(e => e.Customer).WithMany(e => e.Orders);
            modelBuilder.Entity<Order>().HasRequired<OrderState>(e => e.OrderState).WithMany(e => e.Orders);
            modelBuilder.Entity<OrderDetail>().HasRequired<Order>(e => e.Order).WithMany(e => e.OrderDetails);
            modelBuilder.Entity<OrderDetail>().HasRequired<ProductDetail>(e => e.ProductDetail).WithMany(e => e.OrderDetails);
            modelBuilder.Entity<Product>().HasRequired<Subcategory>(e => e.Subcategory).WithMany(e => e.Products);
            modelBuilder.Entity<ProductDetail>().HasRequired<Product>(e => e.Product).WithMany(e => e.ProductDetails);
            modelBuilder.Entity<Review>().HasRequired<Customer>(e => e.Customer).WithMany(e => e.Reviews);
            modelBuilder.Entity<Review>().HasRequired<Product>(e => e.Product).WithMany(e => e.Reviews);
            modelBuilder.Entity<Subcategory>().HasRequired<Category>(e => e.Category).WithMany(e => e.Subcategories);
            modelBuilder.Entity<Category>().HasMany<Subcategory>(e => e.Subcategories).WithRequired(e => e.Category).WillCascadeOnDelete(false);
            modelBuilder.Entity<Customer>().HasMany<Review>(e => e.Reviews).WithRequired(e => e.Customer).WillCascadeOnDelete(false);
            modelBuilder.Entity<Customer>().HasMany<Order>(e => e.Orders).WithRequired(e => e.Customer).WillCascadeOnDelete(false);
            modelBuilder.Entity<Customer>().HasMany<Address>(e => e.Addresses).WithRequired(e => e.Customer).WillCascadeOnDelete(false);
            modelBuilder.Entity<Option>().HasMany<ProductDetail>(e => e.ProductDetails).WithMany(e => e.Option);
            modelBuilder.Entity<OptionType>().HasMany<Option>(e => e.Options).WithRequired(e => e.OptionType).WillCascadeOnDelete(false);
            modelBuilder.Entity<Order>().HasMany<OrderDetail>(e => e.OrderDetails).WithRequired(e => e.Order).WillCascadeOnDelete(false);
            modelBuilder.Entity<OrderState>().HasMany<Order>(e => e.Orders).WithRequired(e => e.OrderState).WillCascadeOnDelete(false);
            modelBuilder.Entity<Product>().HasMany<Image>(e => e.Images).WithRequired(e => e.Product).WillCascadeOnDelete(false);
            modelBuilder.Entity<Product>().HasMany<Review>(e => e.Reviews).WithRequired(e => e.Product).WillCascadeOnDelete(false);
            modelBuilder.Entity<Product>().HasMany<ProductDetail>(e => e.ProductDetails).WithRequired(e => e.Product).WillCascadeOnDelete(false);
            modelBuilder.Entity<ProductDetail>().HasMany<OrderDetail>(e => e.OrderDetails).WithRequired(e => e.ProductDetail).WillCascadeOnDelete(false);
            modelBuilder.Entity<Subcategory>().HasMany<Product>(e => e.Products).WithRequired(e => e.Subcategory).WillCascadeOnDelete(false);
        }

        public override int SaveChanges()
        {
            return base.SaveChanges();
        }

        public virtual T EntryWithState<T>(T entity, EntityState state) where T : class
        {
            if (entity == null)
                return null;

            var objContext = ((IObjectContextAdapter)this).ObjectContext;
            var objSet = objContext.CreateObjectSet<T>();
            var entityKey = objContext.CreateEntityKey(objSet.EntitySet.Name, entity);

            object foundState;

            var exists = objContext.TryGetObjectByKey(entityKey, out foundState);
            if (exists)
            {
                objContext.ObjectStateManager.ChangeObjectState(foundState, state);
                return (foundState as T);
            }
            else
            {
                DbEntityEntry entry = this.Entry(entity);
                entry.State = state;
                return entry.Entity as T;
            }
        }
    }
}
